{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vpPz7G_N6gpp"
      },
      "source": [
        "\n",
        "<a href=\"https://colab.research.google.com/drive/1xZ_QyAFtg2pGv_USPAfdfHRiVu1a1cFb?usp=sharing\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"></a>\n",
        "\n",
        "🦙 [Prompt Engineering with Ollama + Llama 3.x or DeepSeek based Open source LLMs](https://colab.research.google.com/drive/1BKhDfx45YEpMMisDnn5V_Rvlh_gHImGe?usp=sharing)&nbsp;&nbsp;\n",
        "\n",
        "</div>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HxxOWz9dpsYj"
      },
      "source": [
        "### 📚 Prompt Engineering\n",
        "\n",
        "[Prompt Engineering](https://www.promptingguide.ai/introduction) is the **art** and **science** of crafting effective inputs for Large Language Models (LLMs) to produce desired outputs. It's a crucial skill in GenAI related tasks, allowing users to harness the full potential of Large Language Models (LLMs) for various tasks.\n",
        "\n",
        "------------\n",
        "\n",
        "#### 📖 Fundamentals of Prompt Design\n",
        "\n",
        "  * #### ✨ Clarity\n",
        "    * Be specific and unambiguous in your instructions.\n",
        "\n",
        "  * #### 🏛️ Context\n",
        "    * Provide relevant background information.\n",
        "\n",
        "  * #### 🚧 Constraints\n",
        "    * Set boundaries for the AI's response.\n",
        "\n",
        "  * #### 🧪 Examples\n",
        "    * Include sample inputs and outputs when possible.\n",
        "\n",
        "  * #### 🗂️ Format\n",
        "    * Specify the desired structure of the response.\n",
        "\n",
        "------------\n",
        "<br>\n",
        "\n",
        "<img width=\"700\" src=\"https://raw.githubusercontent.com/genieincodebottle/generative-ai/main/images/Prompt_engineering.png\">\n",
        "\n",
        "#### 📌 Important Prompt Techniques you should know\n",
        "\n",
        "  1. #### 🧠 Chain of Thought (CoT)\n",
        "    * A strategy to enhance reasoning by articulating intermediate steps.\n",
        "\n",
        "  2. #### 🚀 Zero-Shot Chain of Thought (Zero-Shot-CoT)\n",
        "    * Applying CoT without prior examples or training on similar tasks.\n",
        "\n",
        "  3. #### 🎯 Few-Shot Chain of Thought  (Few-Shot-CoT)\n",
        "    * Using a few examples to guide the reasoning process.\n",
        "\n",
        "  4. #### 🤔 ReAct (Reasoning and Acting)\n",
        "    * Combining reasoning with action to improve responses.\n",
        "\n",
        "  5. #### 🌳 Tree of Thoughts (ToT)\n",
        "    * Organizing thoughts hierarchically for better decision-making.\n",
        "\n",
        "  6. #### 🔄 Self-Consistency\n",
        "    * Ensuring responses are stable and consistent across queries.\n",
        "\n",
        "  7. #### 📄 Hypothetical Document Embeddings (HyDE)\n",
        "    * Leveraging embeddings to represent potential documents for reasoning.\n",
        "\n",
        "  8. #### 🏗️ Least-to-Most Prompting\n",
        "    * Starting with simpler prompts and gradually increasing complexity.\n",
        "\n",
        "  9. #### 🔗 Prompt Chaining\n",
        "    * Connecting multiple prompts to create a coherent narrative.\n",
        "\n",
        "  10. #### 📊 Graph Prompting\n",
        "    * Using graph structures to represent complex relationships.\n",
        "\n",
        "  11. #### 🔄 Recursive Prompting\n",
        "    * Iteratively refining prompts to enhance results.\n",
        "\n",
        "  12. #### 💡 Generated Knowledge\n",
        "    * Utilizing generated content as a basis for further reasoning.\n",
        "\n",
        "  13. #### ⚙️ Automatic Reasoning and Tool-Use (ART)\n",
        "    * Automating reasoning processes and tool interactions.\n",
        "\n",
        "  14. #### 🛠️ Automatic Prompt Engineer (APE)\n",
        "    * Tools to automatically generate and refine prompts.\n",
        "\n",
        "  15. #### ✨ Additional Prompt Techniques\n",
        "    * **Reflexion**: Reflecting on past responses to improve future prompts.\n",
        "    \n",
        "    * **Prompt Ensembling**: Combining multiple prompts for enhanced results.\n",
        "    \n",
        "    * **Directional Stimulus Prompting**: Guiding responses with targeted prompts.\n",
        "\n",
        "------------\n",
        "<br>\n",
        "\n",
        "#### 📈 Prompt Optimization Techniques\n",
        "\n",
        "1. **Iterative refinement:** Start with a basic prompt and gradually improve it based on the results.\n",
        "\n",
        "2. [**A/B testing:**](https://www.oracle.com/in/cx/marketing/what-is-ab-testing/#:~:text=A%2FB%20testing%3F-,A%2FB%20testing%20definition,based%20on%20your%20key%20metrics.) Compare different versions of a prompt to see which performs better.\n",
        "\n",
        "3. **Prompt libraries:** Create and maintain a collection of effective prompts for reuse.\n",
        "\n",
        "4. **Collaborative prompting:** Combine insights from multiple team members to create stronger prompts.\n",
        "------------\n",
        "<br>\n",
        "\n",
        "### ⚖️ Ethical Considerations in Prompt Engineering\n",
        "\n",
        "1. **Bias mitigation:** Be aware of and actively work to reduce biases in prompts and outputs.\n",
        "\n",
        "2. **Content safety:** Implement safeguards against generating harmful or inappropriate content.\n",
        "\n",
        "4. **Data privacy:** Avoid including sensitive information in prompts.\n",
        "------------\n",
        "<br>\n",
        "\n",
        "#### ✅ Evaluating Prompt Effectiveness\n",
        "\n",
        "1. **Relevance:** Does the output address the intended task or question?\n",
        "\n",
        "2. **Accuracy:** Is the information provided correct and up-to-date?\n",
        "\n",
        "3. **Coherence:** Is the response well-structured and logical?\n",
        "\n",
        "4. **Creativity:** For open-ended tasks, does the output demonstrate originality?\n",
        "\n",
        "5. **Efficiency:** Does the prompt produce the desired result with minimal back-and-forth?"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Y3axTI0sp5Hg"
      },
      "source": [
        "### 📦 Install required libraries"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "collapsed": true,
        "id": "ShxTNxM5gqtr",
        "outputId": "2b3be410-944b-4c44-ae18-fbe5d3d42601"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\u001b[?25l   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m0.0/42.0 kB\u001b[0m \u001b[31m?\u001b[0m eta \u001b[36m-:--:--\u001b[0m\r\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m42.0/42.0 kB\u001b[0m \u001b[31m1.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25h"
          ]
        }
      ],
      "source": [
        "!pip install -qU \\\n",
        "     langchain==0.3.19 \\\n",
        "     langchain-community==0.3.18 \\\n",
        "     langchain-groq==0.2.4 \\ # If using Groq based free Open Source LLMS\n",
        "     langchain-google-genai==2.0.10 \\ # If using Google's Gemini LLMs\n",
        "     langchain-openai==0.3.7 \\ # If using OpenAI LLMs\n",
        "     langchain-anthropic==0.3.8 # If using Anthropic's Claude LLMs"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9jJ1vqs-p_Zx"
      },
      "source": [
        "### 📥 Import related libraries"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "id": "RL-3LsYogoH5"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "import getpass\n",
        "import json\n",
        "from typing import List, Dict, Union\n",
        "\n",
        "# If using Google's Gemini LLMs\n",
        "from langchain_google_genai import (\n",
        "    ChatGoogleGenerativeAI,\n",
        "    HarmBlockThreshold,\n",
        "    HarmCategory,\n",
        ")\n",
        "# If using Groq API based Open source LLMs\n",
        "from langchain_groq import ChatGroq\n",
        "# If using OpenAI LLMs\n",
        "from langchain_openai import ChatOpenAI\n",
        "# For OpenAI LLMs\n",
        "from langchain_anthropic import ChatAnthropic\n",
        "\n",
        "from langchain.prompts import ChatPromptTemplate\n",
        "from langchain.schema import HumanMessage, SystemMessage\n",
        "from langchain_core.output_parsers import StrOutputParser\n",
        "from IPython.display import display, Markdown"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Usf-u8jneT_n"
      },
      "source": [
        "### 🔑 If using Groq API Key\n",
        "  Use below link to generate free Groq API Key for Opensource LLMs\n",
        "  - [Groq API Key](https://console.groq.com/keys)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "o96n6zApeffH"
      },
      "outputs": [],
      "source": [
        "os.environ[\"GROQ_API_KEY\"] = getpass.getpass()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VhYHpvHol481"
      },
      "outputs": [],
      "source": [
        "# If you want to use Groq API then uncomment following\n",
        "\"\"\"\n",
        "llm = ChatGroq(\n",
        "    model=\"llama-3.1-8b-instant\",\n",
        "    temperature=0.5\n",
        ")\n",
        "\"\"\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "524I_MmIxLIP"
      },
      "source": [
        "### 🔑 If using OpenAI API\n",
        "\n",
        "  - [Open API Key Generation](https://platform.openai.com/api-keys)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3b9CNu24xYMb"
      },
      "outputs": [],
      "source": [
        "os.environ[\"OPENAI_API_KEY\"] = getpass.getpass()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "y6pp6vxjxYXQ"
      },
      "outputs": [],
      "source": [
        "# If you want to use OpenAI API then uncomment following\n",
        "\"\"\"\n",
        "llm = ChatOpenAI(\n",
        "    model=\"gpt-5-2025-08-07\",\n",
        "    temperature=0.5\n",
        ")\n",
        "\"\"\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bgUuJ3XJyWf4"
      },
      "source": [
        "### 🔑 If using Anthropic's Claude API\n",
        "\n",
        "  - [Anthropic API Key Generation](https://console.anthropic.com/settings/keys)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "vL-m1iboy90A"
      },
      "outputs": [],
      "source": [
        "os.environ[\"ANTHROPIC_API_KEY\"] = getpass.getpass()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JQ2BNIFWy9_Q"
      },
      "outputs": [],
      "source": [
        "# If you want to use Anthropic's Claude API then uncomment following\n",
        "\"\"\"\n",
        "llm = ChatAnthropic(\n",
        "    model=\"claude-sonnet-4-20250514\",\n",
        "    temperature=0.5\n",
        ")\n",
        "\"\"\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qh53S_JUzlwE"
      },
      "source": [
        "### 🔑 If using Google API Key\n",
        "\n",
        "1. [Google's Gemini API Key](https://ai.google.dev/gemini-api/docs/api-key)\n",
        "\n",
        "2. [YouTube Video explaining Google API Key](https://www.youtube.com/watch?v=ZHX7zxvDfoc)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "9x763SU1zoVU"
      },
      "outputs": [],
      "source": [
        "os.environ[\"GOOGLE_API_KEY\"] = getpass.getpass()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DAL52x3u4o8_"
      },
      "source": [
        "### If using Google's Gemini API -> Create instance of Google's free gemini models\n",
        "\n",
        "Using Langchain's **\"langchain-google-genai\"** library\n",
        "\n",
        "#### 🔬 For Gemini Models, we can experiment with following LLM Parameters\n",
        "\n",
        "* `temperature`\n",
        "\n",
        "  This parameter controls the randomness of the model's output. A lower temperature (closer to 0) makes the output more deterministic and focused, while a higher temperature (closer to 1) makes it more random and creative.\n",
        "  * **Range:** Usually 0 to 1\n",
        "  * **Default:** Often around 0.7, but this can vary\n",
        "  * **Use cases:** Lower for factual or precise tasks, higher for creative tasks\n",
        "\n",
        "* `max_output_tokens`\n",
        "\n",
        "  This sets the maximum length of the generated text in tokens. A token is generally a word or a part of a word.\n",
        "  * **Range:** Model-dependent, but often up to several thousand\n",
        "  * **Default:** Varies, but often around 1024 or 2048\n",
        "  * **Use cases:** Adjust based on the desired length of the response\n",
        "\n",
        "* `top_p (nucleus sampling)`\n",
        "  \n",
        "  This parameter sets a probability threshold for token selection. The model will only consider tokens whose cumulative probability exceeds this threshold.\n",
        "  * **Range:** 0 to 1\n",
        "  * **Default:** Often around 0.9\n",
        "  * **Use cases:** Lower values make output more focused, higher values allow for more diversity\n",
        "\n",
        "* `top_k`\n",
        "  \n",
        "  This parameter limits the number of highest probability tokens to consider at each step of generation.\n",
        "  * **Range:** Positive integers, often up to 100 or more\n",
        "  * **Default:** Often around 40\n",
        "  * **Use cases:** Lower values for more predictable output, higher for more variety\n",
        "--------------------\n",
        "<br>\n",
        "\n",
        "### 📋 General best practices\n",
        "\n",
        "* Experiment with different combinations to find what works best for your specific use case.\n",
        "\n",
        "* Avoid adjusting all parameters at once; change one at a time to understand its impact.\n",
        "\n",
        "* For factual or critical tasks, prioritize lower temperature or `top_p` values.\n",
        "\n",
        "* For creative tasks, higher `temperature` or `top_p` values can be beneficial.\n",
        "Consider the trade-off between creativity and accuracy when adjusting these parameters.\n",
        "\n",
        "* Document successful parameter combinations for different types of tasks.\n",
        "Regularly review and update your parameter choices as model capabilities evolve.\n",
        "\n",
        "--------------------\n",
        "<br>\n",
        "\n",
        "### 🛡️ Safety Settings\n",
        "\n",
        "* Gemini Pro likely categorizes potential harms into these four main categories:\n",
        "\n",
        "  * Hate Speech\n",
        "\n",
        "  * Dangerous Content\n",
        "\n",
        "  * Sexually Explicit Content\n",
        "\n",
        "  * Harassment\n",
        "\n",
        "* **HarmBlockThreshold:**\n",
        "  This is probably an enum in Gemini Pro's API that defines different levels of content filtering. While I don't know the exact levels, they might include:\n",
        "\n",
        "  * BLOCK_NONE: No filtering\n",
        "\n",
        "  * BLOCK_LOW: Minimal filtering\n",
        "\n",
        "  * BLOCK_MEDIUM: Moderate filtering\n",
        "\n",
        "  * BLOCK_HIGH: Strict filtering\n",
        "\n",
        "* **Implementation:**\n",
        "\n",
        "  * When set to BLOCK_NONE for all categories, Gemini Pro likely bypasses its content filtering mechanisms for these specific harm types.\n",
        "\n",
        "  * This doesn't mean the model will necessarily produce harmful content, but rather that it won't actively filter or block content in these categories."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Ye3dDZF0IJzP"
      },
      "outputs": [],
      "source": [
        "llm = ChatGoogleGenerativeAI(\n",
        "    model=\"gemini-2.5-pro\",\n",
        "    temperature=0.1,  # Experiment with temperature setting\n",
        "    # top_k=40, # Experiment with top_k setting\n",
        "    # top_p=0.95, # Experiment with top_p setting\n",
        "    safety_settings={\n",
        "        HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,\n",
        "        HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,\n",
        "        HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,\n",
        "        HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,\n",
        "    },\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "C48uwYpp47IM"
      },
      "source": [
        "### 📌 Prompt Techniques with Code\n",
        "\n",
        "Let's dive deep... :)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "iQUYayVAM3CZ"
      },
      "source": [
        "### 🧠 Chain of Thought (CoT)\n",
        "\n",
        "Chain of Thought is a method that encourages language models to show their reasoning process step-by-step.\n",
        "\n",
        "### Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Prompt the model to break down complex reasoning into explicit intermediate steps.\n",
        "\n",
        "* ⚙️ **Process:**\n",
        "  * Provide a question or problem\n",
        "  * Ask the model to think through the solution step-by-step\n",
        "  * Generate a final answer based on the reasoning chain\n",
        "\n",
        "* 🌟 **Advantages:**\n",
        "  * Improves accuracy on complex tasks\n",
        "  * Enhances transparency of the model's decision-making\n",
        "\n",
        "* 💼 **Applications:**\n",
        "  * Mathematical problem-solving\n",
        "  * Logical reasoning\n",
        "  * Multi-step analysis tasks\n",
        "  \n",
        "* 🚀 **Implementation:**\n",
        "  * Use prompts like \"Let's approach this step-by-step:\" or \"Think through this carefully:\"\n",
        "  * Can include examples of step-by-step reasoning (few-shot approach)\n",
        "  \n",
        "* 🔄 **Variations:**\n",
        "  * Zero-shot CoT: No examples provided\n",
        "  * Few-shot CoT: Includes examples of desired reasoning\n",
        "\n",
        "* ⚖️ **Challenges:**\n",
        "  * Ensuring coherence across reasoning steps\n",
        "  * Balancing detail with conciseness\n",
        "\n",
        "* 📝 **Example structure:**\n",
        "  * Problem: [Task description]\n",
        "  * Let's solve this step-by-step:\n",
        "\n",
        "    [First reasoning step]\n",
        "    [Second reasoning step]\n",
        "    ...\n",
        "    Therefore, the answer is [final conclusion]\""
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 321
        },
        "id": "V_LFCcf7IJ19",
        "outputId": "83c9f26c-6381-408a-e66b-f21213d4b065"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**Chain of Thought Response:**\n",
              "Okay, let's solve this problem step-by-step:\n",
              "\n",
              "**1. Understand the concept of average speed:**\n",
              "\n",
              "*   Average speed is calculated by dividing the total distance traveled by the total time taken.\n",
              "\n",
              "**2. Identify the given information:**\n",
              "\n",
              "*   Distance traveled: 120 km\n",
              "*   Time taken: 2 hours\n",
              "\n",
              "**3. Apply the formula for average speed:**\n",
              "\n",
              "*   Average speed = Total distance / Total time\n",
              "\n",
              "**4. Substitute the given values into the formula:**\n",
              "\n",
              "*   Average speed = 120 km / 2 hours\n",
              "\n",
              "**5. Calculate the result:**\n",
              "\n",
              "*   Average speed = 60 km/h\n",
              "\n",
              "**Answer:** The average speed of the train is 60 km/h."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "cot_prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        (\"system\", \"You are a helpful assistant that explains problems step-by-step.\"),\n",
        "        (\"human\", \"Solve this problem step by step: {input}\"),\n",
        "    ]\n",
        ")\n",
        "\n",
        "chain = cot_prompt | llm\n",
        "problem = \"If a train travels 120 km in 2 hours, what is its average speed in km/h?\"\n",
        "response = chain.invoke({\"input\": problem})\n",
        "\n",
        "display(Markdown(f\"**Chain of Thought Response:**\\n{response.content}\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0jV8Y-KdSqVA"
      },
      "source": [
        "### 🚀 Zero-Shot Chain of Thought (Zero-Shot-CoT)\n",
        "\n",
        "Zero-Shot-CoT is a variation of Chain of Thought prompting that doesn't rely on examples.\n",
        "\n",
        "#### Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Encourages step-by-step reasoning without providing sample solutions.\n",
        "\n",
        "* 📝 **Prompt structure:** Typically includes phrases like \"Let's approach this step-by-step\" or \"Let's think about this logically.\"\n",
        "\n",
        "* 🌟 **Advantage:** Flexibility across various tasks without task-specific examples.\n",
        "\n",
        "* ⚖️ **Challenge:** Relies heavily on the model's inherent reasoning capabilities.\n",
        "\n",
        "* 💼 **Applications:** Problem-solving, analysis, and decision-making across diverse domains.\n",
        "\n",
        "* 🚀 **Implementation:** Often uses a two-stage process - reasoning generation followed by answer extraction.\n",
        "\n",
        "* 📝 **Example prompt:** \"Let's solve this problem step-by-step: [insert problem]\"\n",
        "\n",
        "* 📈 **Effectiveness:** Can significantly improve performance on complex tasks compared to direct questioning."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 197
        },
        "id": "2pSXe7DcIJ4b",
        "outputId": "e8d3c23e-64bb-4db3-d9be-9722bbd9ae33"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**Zero-Shot Chain of Thought Response:**\n",
              "Okay, let's break this problem down:\n",
              "\n",
              "1. **Find the number of rotten apples:** We know that 20% of the 100 apples are rotten.  To find 20% of 100, we can multiply 0.20 by 100.\n",
              "\n",
              "2. **Calculate:** 0.20 * 100 = 20 rotten apples.\n",
              "\n",
              "3. **Find the number of good apples:**  We started with 100 apples and 20 are rotten.  To find the number of good apples, we subtract the number of rotten apples from the total number of apples.\n",
              "\n",
              "4. **Calculate:** 100 - 20 = 80 good apples.\n",
              "\n",
              "**Answer:** There are 80 good apples left."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "zero_shot_cot_prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        (\"system\", \"Approach problems step-by-step, explaining your reasoning at each stage.\"),\n",
        "        (\"human\", \"Q: {input}\\nA: Let's approach this step-by-step:\"),\n",
        "    ]\n",
        ")\n",
        "\n",
        "chain = zero_shot_cot_prompt | llm\n",
        "question = \"A store has 100 apples. If 20% of the apples are rotten, how many good apples are left?\"\n",
        "response = chain.invoke({\"input\": question})\n",
        "\n",
        "display(Markdown(f\"**Zero-Shot Chain of Thought Response:**\\n{response.content}\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hEmvcu_STSwD"
      },
      "source": [
        "### 🎯 Few-Shot Chain of Thought (Few-Shot-CoT)\n",
        "\n",
        "Few-Shot-CoT is a prompting technique that provides examples of step-by-step reasoning before asking the model to solve a new problem.\n",
        "\n",
        "#### Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Uses 1-5 examples of reasoning chains to guide the model's approach to new problems.\n",
        "\n",
        "* 📝 **Structure:** Includes example problems, their step-by-step solutions, and then a new problem to solve.\n",
        "\n",
        "* 🌟 **Advantage:** Improves performance by demonstrating the desired reasoning process.\n",
        "\n",
        "* 💼 **Applications:** Complex problem-solving, mathematical reasoning, logical deductions.\n",
        "\n",
        "* 🚀 **Implementation:** Carefully select diverse, relevant examples that showcase the desired reasoning style.\n",
        "\n",
        "* ⚖️ **Challenges:** Choosing appropriate examples and avoiding biasing the model.\n",
        "\n",
        "* 📝 **Example:**\n",
        "  * [Example problem 1]\n",
        "    Step 1: [Reasoning]\n",
        "    Step 2: [Reasoning]\n",
        "  * Answer: [Solution]\n",
        "    Now, solve this new problem using the same approach: [New problem]\n",
        "\n",
        "* 📈 **Effectiveness:** Often outperforms zero-shot techniques, especially on complex tasks."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 210
        },
        "id": "uL1a363BIJ7F",
        "outputId": "f7e3e53e-7d43-4602-982f-20698516f7ce"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**Few-Shot Chain of Thought Response:**\n",
              "Here's how to calculate the area of a circle with a radius of 5cm:\n",
              "\n",
              "1)  The formula for the area of a circle is: Area = π * r^2, where π (pi) is approximately 3.14159 and r is the radius of the circle.\n",
              "\n",
              "2)  We are given that the radius (r) is 5cm.\n",
              "\n",
              "3)  Substitute the value of the radius into the formula: Area = π * (5cm)^2\n",
              "\n",
              "4)  Calculate 5cm squared: (5cm)^2 = 25 cm^2\n",
              "\n",
              "5)  Multiply by π: Area = π * 25 cm^2 ≈ 3.14159 * 25 cm^2\n",
              "\n",
              "6)  Calculate the final area: Area ≈ 78.53975 cm^2\n",
              "\n",
              "Therefore, the area of a circle with a radius of 5cm is approximately 78.54 cm^2."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "few_shot_cot_prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        (\"system\", \"You are an expert at solving problems step-by-step.\"),\n",
        "        (\"human\", \"\"\"Here are some examples of solving problems step-by-step:\n",
        "\n",
        "          Q: What is 17 x 23?\n",
        "          A: Let's break it down:\n",
        "          1) First, let's multiply 17 by 20: 17 x 20 = 340\n",
        "          2) Now, let's multiply 17 by 3: 17 x 3 = 51\n",
        "          3) Finally, we add these results: 340 + 51 = 391\n",
        "          Therefore, 17 x 23 = 391\n",
        "\n",
        "          Q: How many seconds are in a day?\n",
        "          A: Let's calculate step-by-step:\n",
        "          1) There are 24 hours in a day\n",
        "          2) Each hour has 60 minutes\n",
        "          3) Each minute has 60 seconds\n",
        "          4) So, we calculate: 24 x 60 x 60\n",
        "          5) 24 x 60 = 1,440\n",
        "          6) 1,440 x 60 = 86,400\n",
        "          Therefore, there are 86,400 seconds in a day.\n",
        "\n",
        "          Now, solve this problem step-by-step:\n",
        "          Q: {input}\n",
        "          A: Let's break it down:\"\"\"),\n",
        "    ]\n",
        ")\n",
        "\n",
        "chain = few_shot_cot_prompt | llm\n",
        "question = \"What is the area of a circle with radius 5cm?\"\n",
        "response = chain.invoke({\"input\": question})\n",
        "\n",
        "display(Markdown(f\"**Few-Shot Chain of Thought Response:**\\n{response.content}\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jhd6nHXzUVXj"
      },
      "source": [
        "# 🤔 ReACT (Reasoning and Acting)\n",
        "\n",
        "ReAct is an advanced prompting method that combines reasoning and acting in language models.\n",
        "\n",
        "## Key points\n",
        "\n",
        "* 🔑 **Core concept:** Interleaves thought generation with action execution.\n",
        "\n",
        "* 🛠️ **Components:** Thought, Action, Observation cycle.\n",
        "\n",
        "* ⚙️ **Process:**\n",
        "  * **Thought:** Model reasons about the current state\n",
        "  * **Action:** Decides on and executes an action\n",
        "  * **Observation:** Receives feedback from the environment\n",
        "\n",
        "* 💼 **Applications:** Task-solving, information retrieval, decision-making.\n",
        "\n",
        "* 🌟 **Advantages:**\n",
        "  * Improves problem-solving abilities\n",
        "  * Enhances model's interaction with external tools/data\n",
        "\n",
        "* 🚀 **Implementation:** Uses specific prompts to guide the model through the Thought-Action-Observation cycle.\n",
        "\n",
        "* 📝 **Example structure:**\n",
        "  * **Thought:** [Reasoning about the task]\n",
        "  * **Action:** [Chosen action, e.g., 'Search for X']\n",
        "  * **Observation:** [Result of the action]\n",
        "  * **Thought:** [Next step based on observation]\n",
        "\n",
        "* 📈 **Use cases:** Web navigation, complex multi-step tasks, interactive problem-solving."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 284
        },
        "id": "f6jozW4CIJ9p",
        "outputId": "0a550e25-5f7f-4573-aaef-b2c962f46279"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**ReAct Response:**\n",
              "Okay, let's break this down step-by-step.\n",
              "\n",
              "1.  **Analyze the task and identify key components:** The task is to calculate the area of a circle. We are given the radius of the circle, which is 5 cm.\n",
              "\n",
              "2.  **Determine what information or actions are needed:** We need the formula for the area of a circle. Then, we need to substitute the given radius into the formula and calculate the area.\n",
              "\n",
              "3.  **Information needed:** The formula for the area of a circle.\n",
              "\n",
              "4.  **Action:** Recall the formula for the area of a circle. The area of a circle is given by the formula: Area = π * r², where π (pi) is approximately 3.14159 and r is the radius of the circle.\n",
              "\n",
              "5.  **Action:** Substitute the given radius (r = 5 cm) into the formula: Area = π * (5 cm)²\n",
              "\n",
              "6.  **Action:** Calculate the area: Area = π * 25 cm² ≈ 3.14159 * 25 cm² ≈ 78.53975 cm²\n",
              "\n",
              "7.  **Action:** Round the answer to a reasonable number of decimal places. Let's round to two decimal places. Area ≈ 78.54 cm²\n",
              "\n",
              "**Final Answer:** The area of a circle with radius 5 cm is approximately 78.54 cm²."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "react_prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        (\"system\", \"You are an AI assistant capable of reasoning and acting. Approach tasks step-by-step, explaining your thought process and actions.\"),\n",
        "        (\"human\", \"\"\"Task: {input}\n",
        "\n",
        "            Think through this task step by step:\n",
        "            1) Analyze the task and identify key components\n",
        "            2) Determine what information or actions are needed\n",
        "            3) If information is needed, state what you need to know\n",
        "            4) If an action is needed, describe the action\n",
        "            5) Repeat steps 3-4 until the task is complete\n",
        "            6) Provide the final answer or solution\n",
        "\n",
        "            Your response:\"\"\"\n",
        "        ),\n",
        "    ]\n",
        ")\n",
        "\n",
        "chain = react_prompt | llm\n",
        "task = \"Calculate the total cost of a shopping trip where you buy 3 apples at $0.50 each and 2 loaves of bread at $2.25 each. Don't forget to add 8% sales tax.\"\n",
        "response = chain.invoke({\"input\": question})\n",
        "\n",
        "display(Markdown(f\"**ReAct Response:**\\n{response.content}\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b667A5ROU6Mx"
      },
      "source": [
        "# 🌳 Tree of Thoughts (ToT)\n",
        "\n",
        "Tree of Thoughts is an advanced prompting method that explores multiple reasoning paths simultaneously.\n",
        "\n",
        "## Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Generates and evaluates multiple \"thoughts\" at each step of reasoning.\n",
        "\n",
        "* 📊 **Structure:** Creates a tree-like structure of potential solution paths.\n",
        "\n",
        "* ⚙️ **Process:**\n",
        "  * Generate multiple initial thoughts\n",
        "  * Evaluate and expand promising thoughts\n",
        "  * Prune less promising branches\n",
        "  * Iterate until reaching a solution\n",
        "\n",
        "* 🌟 **Advantages:**\n",
        "  * Explores diverse problem-solving approaches\n",
        "  * Reduces chances of getting stuck in suboptimal reasoning paths\n",
        "\n",
        "* 💼 **Applications:** Complex problem-solving, strategic planning, creative tasks.\n",
        "\n",
        "* 🚀 **Implementation:** Requires careful prompting to guide thought generation and evaluation.\n",
        "\n",
        "* 🔑 **Key components:**\n",
        "  * Thought generator\n",
        "  * State evaluator\n",
        "  * Search algorithm (e.g., breadth-first, depth-first)\n",
        "\n",
        "* ⚖️**Challenges:** Balancing exploration breadth with computational efficiency."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 918
        },
        "id": "rDfnsXpKIJ_0",
        "outputId": "dae7d4dc-6b88-49f9-8e5b-6cf6a79c3729"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**Tree of Thoughts Response:**\n",
              "Okay, I can explore multiple solution paths to find the area of a circle with a radius of 5cm.\n",
              "\n",
              "**Approach 1: Direct Formula Application**\n",
              "\n",
              "*   **Concept:** Use the standard formula for the area of a circle, which directly relates the area to the radius.\n",
              "*   **Formula:** Area (A) = πr², where r is the radius.\n",
              "*   **Calculation:**\n",
              "    *   A = π * (5 cm)²\n",
              "    *   A = π * 25 cm²\n",
              "    *   A ≈ 3.14159 * 25 cm²\n",
              "    *   A ≈ 78.54 cm² (rounded to two decimal places)\n",
              "\n",
              "**Approach 2: Using Diameter and Radius Relationship**\n",
              "\n",
              "*   **Concept:** First, calculate the diameter using the radius, then use a modified area formula that incorporates the diameter.\n",
              "*   **Formula:**\n",
              "    *   Diameter (d) = 2 * r\n",
              "    *   Area (A) = π * (d/2)²  (This is just a rearrangement of the standard formula)\n",
              "*   **Calculation:**\n",
              "    *   d = 2 * 5 cm = 10 cm\n",
              "    *   A = π * (10 cm / 2)²\n",
              "    *   A = π * (5 cm)²\n",
              "    *   A = π * 25 cm²\n",
              "    *   A ≈ 3.14159 * 25 cm²\n",
              "    *   A ≈ 78.54 cm² (rounded to two decimal places)\n",
              "\n",
              "**Approach 3: Approximation using inscribed squares**\n",
              "\n",
              "*   **Concept:** Approximate the area of the circle by inscribing a square within it. Calculate the area of the square and then use a scaling factor to estimate the circle's area. This is a less precise method but demonstrates a different problem-solving strategy.\n",
              "*   **Steps:**\n",
              "    1.  Inscribe a square inside the circle. The diagonal of the square is equal to the diameter of the circle (10 cm).\n",
              "    2.  Let 's' be the side of the square. Using the Pythagorean theorem: s² + s² = 10²  => 2s² = 100 => s² = 50 => s = √50 ≈ 7.07 cm\n",
              "    3.  Area of the square = s² = 50 cm²\n",
              "    4.  Scaling factor: Since the circle encompasses the square, we know the circle's area is larger. A reasonable scaling factor could be based on the ratio of the areas of a circumscribed square to the inscribed square. The circumscribed square would have sides equal to the diameter (10cm), so its area is 100cm². The ratio is 100/50 = 2. However, this overestimates the circle. A more refined scaling factor could be around 1.5 to 1.6. Let's use 1.57 (a rough approximation of π/2).\n",
              "    5.  Estimated area of the circle = Area of square * Scaling factor = 50 cm² * 1.57 ≈ 78.5 cm²\n",
              "\n",
              "**Evaluation:**\n",
              "\n",
              "*   **Approach 1 (Direct Formula):** This is the most straightforward, accurate, and efficient method. It directly applies the well-established formula for the area of a circle.\n",
              "*   **Approach 2 (Diameter and Radius Relationship):** This approach is mathematically correct but adds an unnecessary step (calculating the diameter). It ultimately leads back to the same calculation as Approach 1, making it less efficient.\n",
              "*   **Approach 3 (Inscribed Square Approximation):** This approach provides an *approximation* of the area. While it demonstrates a different problem-solving technique, it is less accurate and more complex than the direct formula method. The accuracy depends heavily on the chosen scaling factor.\n",
              "\n",
              "**Best Solution:**\n",
              "\n",
              "The **best solution is Approach 1 (Direct Formula Application)**. It is the most direct, accurate, and efficient way to calculate the area of a circle given its radius. It relies on a fundamental formula and minimizes the number of steps required.\n",
              "\n",
              "*   **Area (A) = πr²**\n",
              "*   **A = π * (5 cm)²**\n",
              "*   **A ≈ 78.54 cm²**"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "tot_prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        (\"system\", \"You are an AI that can explore multiple solution paths for complex problems.\"),\n",
        "        (\"human\", \"\"\"Explore multiple solution paths for this problem:\n",
        "          {input}\n",
        "\n",
        "          Generate three different approaches, then evaluate and choose the best one:\n",
        "\n",
        "          Approach 1:\n",
        "          [Generate first approach]\n",
        "\n",
        "          Approach 2:\n",
        "          [Generate second approach]\n",
        "\n",
        "          Approach 3:\n",
        "          [Generate third approach]\n",
        "\n",
        "          Evaluation:\n",
        "          [Evaluate the three approaches]\n",
        "\n",
        "          Best Solution:\n",
        "          [Choose and explain the best solution]\"\"\"\n",
        "        ),\n",
        "    ]\n",
        ")\n",
        "\n",
        "chain = tot_prompt | llm\n",
        "problem = \"Design a sustainable urban transportation system for a city of 1 million people.\"\n",
        "response = chain.invoke({\"input\": question})\n",
        "\n",
        "# Display the response\n",
        "display(Markdown(f\"**Tree of Thoughts Response:**\\n{response.content}\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ivh8e2yfu6iX"
      },
      "source": [
        "# 🔄 Self-Consistency\n",
        "\n",
        "Self-Consistency is a method to improve the reliability of language model outputs.\n",
        "\n",
        "## Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Generate multiple independent solutions and select the most consistent one.\n",
        "\n",
        "* ⚙️ **Process:**\n",
        "  * Prompt the model multiple times for the same task\n",
        "  * Collect various reasoning paths and answers\n",
        "  * Choose the most common or consistent answer\n",
        "\n",
        "* 🌟 **Advantages:**\n",
        "  * Improves accuracy, especially for complex tasks\n",
        "  * Reduces impact of occasional errors or biases\n",
        "\n",
        "* 💼 **Applications:** Mathematical problem-solving, logical reasoning, decision-making.\n",
        "\n",
        "* 🚀 **Implementation:**\n",
        "  * Use temperature settings to introduce variability\n",
        "  * Prompt for full reasoning chains, not just final answers\n",
        "\n",
        "* **Evaluation:** Can use voting mechanisms or more sophisticated consistency measures.\n",
        "\n",
        "* ⚖️ **Challenges:**\n",
        "  * Increased computational cost\n",
        "  * Handling genuinely ambiguous problems\n",
        "\n",
        "* 🔄 **Variations:** Can be combined with other techniques like Chain of Thought or Tree of Thoughts."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "id": "0ZM68icXIKCg",
        "outputId": "c4ea44c3-a8d8-4a74-ffe5-dec22c2c0524"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**Self-Consistency Response:**\n",
              "Okay, here are three different methods to calculate the volume of a cube with a side length of 4 cm:\n",
              "\n",
              "**Method 1: The Standard Formula**\n",
              "\n",
              "*   **Concept:** The volume of a cube is found by cubing the length of one of its sides.\n",
              "*   **Formula:** Volume (V) = side * side * side = s³\n",
              "*   **Calculation:**\n",
              "    *   V = 4 cm * 4 cm * 4 cm\n",
              "    *   V = 64 cm³\n",
              "\n",
              "**Method 2: Building Up from Area**\n",
              "\n",
              "*   **Concept:**  First, find the area of one face of the cube (which is a square). Then, multiply that area by the height (which is also the side length) to get the volume.\n",
              "*   **Steps:**\n",
              "    1.  **Area of one face:** Area = side * side = 4 cm * 4 cm = 16 cm²\n",
              "    2.  **Volume:** Volume = Area of face * height = 16 cm² * 4 cm = 64 cm³\n",
              "\n",
              "**Method 3: Using Exponential Notation**\n",
              "\n",
              "*   **Concept:** Express the calculation using exponents.\n",
              "*   **Steps:**\n",
              "    1.  **Express the side length:** side = 4 cm\n",
              "    2.  **Volume as an exponent:** Volume = (4 cm)³\n",
              "    3.  **Calculate:** Volume = 4³ cm³ = 64 cm³\n",
              "\n",
              "**Answer:** The volume of the cube is 64 cm³.\n",
              "\n",
              "Okay, here are three different methods to calculate the volume of a cube with a side length of 4 cm:\n",
              "\n",
              "**Method 1: The Standard Formula**\n",
              "\n",
              "*   **Concept:** The volume of a cube is found by cubing the length of one of its sides.\n",
              "*   **Formula:** Volume (V) = side * side * side = s³\n",
              "*   **Calculation:**\n",
              "    *   V = 4 cm * 4 cm * 4 cm\n",
              "    *   V = 64 cm³\n",
              "\n",
              "**Method 2: Building Up From Area**\n",
              "\n",
              "*   **Concept:**  First, find the area of one face of the cube (which is a square). Then, multiply that area by the height (which is also the side length) to get the volume.\n",
              "*   **Steps:**\n",
              "    1.  **Area of one face:** Area = side * side = 4 cm * 4 cm = 16 cm²\n",
              "    2.  **Volume:** Volume = Area of face * height = 16 cm² * 4 cm = 64 cm³\n",
              "\n",
              "**Method 3: Using Exponential Notation**\n",
              "\n",
              "*   **Concept:** Recognize that cubing a number is the same as raising it to the power of 3.\n",
              "*   **Calculation:**\n",
              "    *   Volume = (4 cm)³\n",
              "    *   Volume = 4³ cm³\n",
              "    *   Volume = 64 cm³\n",
              "\n",
              "**Answer:** The volume of the cube is 64 cm³.\n",
              "\n",
              "Okay, here are three different methods to calculate the volume of a cube with a side length of 4 cm:\n",
              "\n",
              "**Method 1: The Standard Formula**\n",
              "\n",
              "*   **Concept:** The volume of a cube is found by cubing the length of one of its sides.\n",
              "*   **Formula:** Volume (V) = side * side * side = s³\n",
              "*   **Calculation:**\n",
              "    *   V = 4 cm * 4 cm * 4 cm\n",
              "    *   V = 64 cm³\n",
              "\n",
              "**Method 2: Building Up from Area**\n",
              "\n",
              "*   **Concept:**  First, find the area of one face of the cube (which is a square). Then, multiply that area by the height (which is also the side length) to get the volume.\n",
              "*   **Steps:**\n",
              "    1.  **Area of one face:** Area = side * side = 4 cm * 4 cm = 16 cm²\n",
              "    2.  **Volume:** Volume = Area of face * height = 16 cm² * 4 cm = 64 cm³\n",
              "\n",
              "**Method 3: Using Exponential Notation**\n",
              "\n",
              "*   **Concept:** Express the calculation using exponents to represent repeated multiplication.\n",
              "*   **Steps:**\n",
              "    1.  **Express the side length:** side = 4 cm\n",
              "    2.  **Volume as an exponent:** Volume = (4 cm)³\n",
              "    3.  **Calculate:** Volume = 4³ cm³ = 64 cm³\n",
              "\n",
              "**Answer:** The volume of the cube is 64 cm³."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "self_consistency_prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        (\"system\", \"You are an AI that can solve problems using multiple approaches.\"),\n",
        "        (\"human\", \"Solve this problem using three different methods: {input}\"),\n",
        "    ]\n",
        ")\n",
        "\n",
        "def self_consistency_response(problem, n_solutions=3):\n",
        "    chain = self_consistency_prompt | llm\n",
        "    solutions = [chain.invoke({\"input\": problem}).content for _ in range(n_solutions)]\n",
        "    # In a real scenario, you'd implement logic to choose the most consistent answer\n",
        "    return \"\\n\\n\".join(solutions)\n",
        "\n",
        "problem = \"What is the volume of a cube with side length 4cm?\"\n",
        "response = self_consistency_response(problem)\n",
        "\n",
        "display(Markdown(f\"**Self-Consistency Response:**\\n{response}\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Yb0lYapgvXHY"
      },
      "source": [
        "# 📄 Hypothetical Document Embeddings (HyDE)\n",
        "\n",
        "HyDE is a method to improve retrieval and question-answering tasks using language models.\n",
        "\n",
        "## Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Generate hypothetical documents to enhance retrieval of relevant information.\n",
        "\n",
        "* ⚙️ **Process:**\n",
        "  * Create a hypothetical answer or document for a given query\n",
        "  * Embed this hypothetical document\n",
        "  * Use the embedding to retrieve similar real documents\n",
        "\n",
        "* 🌟 **Advantages:**\n",
        "  * Improves retrieval accuracy, especially for complex queries\n",
        "  * Bridges the gap between query and document language\n",
        "\n",
        "* 💼 **Applications:** Information retrieval, question-answering systems, search engines.\n",
        "\n",
        "* 🚀 **Implementation:**\n",
        "  * Prompt the model to generate a plausible answer or document\n",
        "  * Use embedding models to convert text to vector representations\n",
        "  * Employ similarity search to find matching real documents\n",
        "\n",
        "* ⚖️ **Challenges:**\n",
        "  * Quality of hypothetical document affects retrieval performance\n",
        "  * Computational overhead of generating and embedding hypothetical documents\n",
        "\n",
        "* 🔄 **Variations:**\n",
        "  * Multi-HyDE: Generate multiple hypothetical documents\n",
        "  * Iterative HyDE: Refine hypothetical documents based on retrieved results\n",
        "\n",
        "* ✔️ **Effectiveness:** Often outperforms traditional keyword-based retrieval methods."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "id": "1deQWbLdIKE8",
        "outputId": "5b21e31d-1563-47dd-e19a-4eb445d5cebc"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**HyDE Response:**\n",
              "Okay, let's walk through how to use multi-modal models within a LangChain chain and then deploy that chain as a REST API using LangServe.  This will cover the core concepts and provide a practical example.\n",
              "\n",
              "**Prerequisites**\n",
              "\n",
              "*   **Python Environment:** Make sure you have Python 3.8+ installed.\n",
              "*   **LangChain, LangServe, and other dependencies:** Install the necessary packages using pip:\n",
              "\n",
              "    ```bash\n",
              "    pip install langchain langchain-openai langchain-community langserve pillow\n",
              "    ```\n",
              "\n",
              "*   **OpenAI API Key:** You'll need an OpenAI API key for the example below. Set it as an environment variable:\n",
              "\n",
              "    ```bash\n",
              "    export OPENAI_API_KEY=\"YOUR_OPENAI_API_KEY\"\n",
              "    ```\n",
              "\n",
              "**Step 1: Building a Multi-Modal Chain**\n",
              "\n",
              "Let's create a simple chain that takes an image as input, uses a multi-modal model (like GPT-4 Vision) to analyze the image, and then returns a description.\n",
              "\n",
              "```python\n",
              "from langchain_openai import ChatOpenAI\n",
              "from langchain_core.prompts import ChatPromptTemplate\n",
              "from langchain_core.output_parsers import StrOutputParser\n",
              "from langchain_core.runnables import RunnablePassthrough\n",
              "import base64\n",
              "import os\n",
              "from PIL import Image\n",
              "from io import BytesIO\n",
              "\n",
              "# 1. Define the Multi-Modal Model\n",
              "model = ChatOpenAI(model=\"gpt-4-vision-preview\", max_tokens=1024)\n",
              "\n",
              "# 2. Create a Prompt\n",
              "prompt = ChatPromptTemplate.from_messages([\n",
              "    (\"user\", \"Describe this image in detail:\\n\\n{image}\"),\n",
              "])\n",
              "\n",
              "# 3. Image Encoding Function (Important for API)\n",
              "def encode_image(image_path):\n",
              "    \"\"\"Encodes an image to base64.\"\"\"\n",
              "    with open(image_path, \"rb\") as image_file:\n",
              "        return base64.b64encode(image_file.read()).decode(\"utf-8\")\n",
              "\n",
              "# 4. Chain Assembly\n",
              "chain = (\n",
              "    {\"image\": RunnablePassthrough()}\n",
              "    | prompt\n",
              "    | model\n",
              "    | StrOutputParser()\n",
              ")\n",
              "\n",
              "# 5. Example Usage (Local)\n",
              "# Replace with the actual path to your image\n",
              "image_path = \"path/to/your/image.jpg\"\n",
              "image_base64 = encode_image(image_path)\n",
              "\n",
              "response = chain.invoke({\"image\": image_base64})\n",
              "print(response)\n",
              "```\n",
              "\n",
              "**Explanation:**\n",
              "\n",
              "1.  **Model Initialization:** We initialize `ChatOpenAI` with the `gpt-4-vision-preview` model.  This is the key to using the multi-modal capabilities.  `max_tokens` controls the length of the output.\n",
              "2.  **Prompt Definition:**  The prompt instructs the model to describe the image.  The `{image}` placeholder will be filled with the base64 encoded image.\n",
              "3.  **Image Encoding:** The `encode_image` function is crucial.  Multi-modal models in LangChain often expect images to be passed as base64 encoded strings, especially when working with APIs.  This function reads the image file, encodes it, and returns the base64 string.\n",
              "4.  **Chain Construction:**\n",
              "    *   `{\"image\": RunnablePassthrough()}`: This part takes the input (which we expect to be a dictionary with an \"image\" key) and passes the value of the \"image\" key directly to the next step.  `RunnablePassthrough` is a LangChain component that simply passes its input along.\n",
              "    *   `| prompt`: This feeds the image (as a base64 string) into the prompt, filling the `{image}` placeholder.\n",
              "    *   `| model`: This sends the filled prompt to the GPT-4 Vision model.\n",
              "    *   `| StrOutputParser()`: This converts the model's output into a plain string.\n",
              "5.  **Local Testing:**  The example usage shows how to invoke the chain locally.  Make sure to replace `\"path/to/your/image.jpg\"` with the actual path to an image file on your system.\n",
              "\n",
              "**Step 2: Deploying the Chain with LangServe**\n",
              "\n",
              "Now, let's deploy this chain as a REST API using LangServe.\n",
              "\n",
              "1.  **Create a `server.py` file:**\n",
              "\n",
              "    ```python\n",
              "    from fastapi import FastAPI\n",
              "    from langserve import add_routes\n",
              "    from your_chain_file import chain  # Import your chain from the previous step\n",
              "\n",
              "    app = FastAPI(\n",
              "        title=\"Multi-Modal Chain API\",\n",
              "        version=\"1.0\",\n",
              "        description=\"A simple API for describing images using GPT-4 Vision.\",\n",
              "    )\n",
              "\n",
              "    add_routes(app, chain, path=\"/describe_image\")\n",
              "\n",
              "    if __name__ == \"__main__\":\n",
              "        import uvicorn\n",
              "        uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n",
              "    ```\n",
              "\n",
              "    *   **`from your_chain_file import chain`**:  Replace `your_chain_file` with the name of the Python file where you defined your chain (e.g., if you saved the previous code as `image_chain.py`, it would be `from image_chain import chain`).\n",
              "    *   **`add_routes(app, chain, path=\"/describe_image\")`**: This line is the magic.  It tells LangServe to create API endpoints for your chain.  The `path` argument specifies the URL path for your API endpoint (e.g., `http://localhost:8000/describe_image`).\n",
              "\n",
              "2.  **Run the LangServe app:**\n",
              "\n",
              "    ```bash\n",
              "    langserve dev server.py\n",
              "    ```\n",
              "\n",
              "    This command starts the LangServe development server.  It will typically run on `http://localhost:8000`.\n",
              "\n",
              "**Step 3: Interacting with the API**\n",
              "\n",
              "Now that your API is running, you can send requests to it.  Here's how you can do it using `curl`:\n",
              "\n",
              "```bash\n",
              "curl -X POST \\\n",
              "  http://localhost:8000/describe_image/invoke \\\n",
              "  -H 'Content-Type: application/json' \\\n",
              "  -d '{\n",
              "    \"input\": {\n",
              "      \"image\": \"YOUR_BASE64_ENCODED_IMAGE\"\n",
              "    }\n",
              "  }'\n",
              "```\n",
              "\n",
              "*   **`http://localhost:8000/describe_image/invoke`**:  This is the endpoint for invoking your chain.  LangServe automatically creates `/invoke`, `/stream`, and `/batch` endpoints.\n",
              "*   **`Content-Type: application/json`**:  Specifies that you're sending JSON data.\n",
              "*   **`\"image\": \"YOUR_BASE64_ENCODED_IMAGE\"`**:  Replace `\"YOUR_BASE64_ENCODED_IMAGE\"` with the actual base64 encoded string of your image.  You can generate this using the `encode_image` function from the first step.\n",
              "\n",
              "**Alternative: Using Python `requests` library**\n",
              "\n",
              "```python\n",
              "import requests\n",
              "import json\n",
              "\n",
              "image_path = \"path/to/your/image.jpg\"\n",
              "with open(image_path, \"rb\") as image_file:\n",
              "    image_data = image_file.read()\n",
              "    image_base64 = base64.b64encode(image_data).decode(\"utf-8\")\n",
              "\n",
              "url = \"http://localhost:8000/describe_image/invoke\"\n",
              "headers = {'Content-type': 'application/json'}\n",
              "data = {\"input\": {\"image\": image_base64}}\n",
              "\n",
              "response = requests.post(url, data=json.dumps(data), headers=headers)\n",
              "\n",
              "if response.status_code == 200:\n",
              "    print(response.json())\n",
              "else:\n",
              "    print(f\"Error: {response.status_code} - {response.text}\")\n",
              "```\n",
              "\n",
              "**Important Considerations and Enhancements**\n",
              "\n",
              "*   **Error Handling:**  Add error handling to your `encode_image` function and within your API to gracefully handle invalid image paths or encoding issues.\n",
              "*   **Input Validation:**  Validate the input to your API to ensure that the \"image\" field is present and contains a valid base64 encoded string.\n",
              "*   **Security:**  If you're deploying this API to a production environment, consider adding authentication and authorization to protect it.\n",
              "*   **Streaming:**  For larger images or more complex chains, consider using the `/stream` endpoint to stream the results back to the client.  This can improve perceived performance.\n",
              "*   **LangSmith Tracing:** Integrate LangSmith into your chain to trace and debug your multi-modal application.  This is invaluable for understanding how the model is processing the images and identifying any bottlenecks.\n",
              "*   **Alternative Multi-Modal Models:** Explore other multi-modal models available through LangChain, such as those from Hugging Face or other providers.  The specific implementation might vary slightly depending on the model.\n",
              "*   **Chaining with other tools:** You can extend this chain to include other tools, such as object detection models, image editing tools, or knowledge bases, to create more sophisticated multi-modal applications.\n",
              "\n",
              "This comprehensive guide should get you started with building and deploying multi-modal chains using LangChain and LangServe. Remember to adapt the code to your specific use case and explore the advanced features of LangChain and LangServe to create powerful and robust LLM-powered applications."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "system = \"\"\"You are an expert about a set of software for building LLM-powered applications called LangChain, LangGraph, LangServe, and LangSmith.\n",
        "\n",
        "        LangChain is a Python framework that provides a large set of integrations that can easily be composed to build LLM applications.\n",
        "        LangGraph is a Python package built on top of LangChain that makes it easy to build stateful, multi-actor LLM applications.\n",
        "        LangServe is a Python package built on top of LangChain that makes it easy to deploy a LangChain application as a REST API.\n",
        "        LangSmith is a platform that makes it easy to trace and test LLM applications.\n",
        "\n",
        "        Answer the user question as best you can. Answer as though you were writing a tutorial that addressed the user question.\"\"\"\n",
        "\n",
        "hyde_prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        (\"system\", system),\n",
        "        (\"human\", \"{input}\"),\n",
        "    ]\n",
        ")\n",
        "\n",
        "chain = hyde_prompt | llm\n",
        "question = \"how to use multi-modal models in a chain and turn chain into a rest api\"\n",
        "response = chain.invoke({\"input\": question})\n",
        "\n",
        "display(Markdown(f\"**HyDE Response:**\\n{response.content}\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "KmDb3TZ5v6DC"
      },
      "source": [
        "# 🏗️ Least-to-Most Prompting\n",
        "\n",
        "Least-to-Most Prompting is a method for breaking down complex problems into simpler, manageable sub-problems.\n",
        "\n",
        "## Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Solve a complex task by addressing easier sub-tasks first.\n",
        "\n",
        "* ⚙️ **Process:**\n",
        "  * Decompose the main problem into sub-problems\n",
        "  * Solve sub-problems in order of increasing difficulty\n",
        "  * Use solutions from earlier steps to inform later ones\n",
        "\n",
        "* 🌟 **Advantages:**\n",
        "  * Improves handling of complex, multi-step problems\n",
        "  * Enhances model's problem-solving capabilities\n",
        "\n",
        "* 💼 **Applications:** Multi-step reasoning, complex math problems, algorithmic tasks.\n",
        "\n",
        "* 🚀 **Implementation:**\n",
        "  * Craft prompts that guide the model to identify sub-problems\n",
        "  * Use intermediate results as context for subsequent steps\n",
        "\n",
        "* ⚖️ **Challenges:**\n",
        "  * Effective problem decomposition\n",
        "  * Maintaining coherence across sub-problems\n",
        "\n",
        "* 📝 **Example structure:**\n",
        "  1. What's the first step to solve [problem]?\n",
        "  2. Given [previous result], what's the next step?\n",
        "  3. Using all previous information, solve [final step].\n",
        "\n",
        "* ✔️ **Effectiveness:** Often leads to more accurate solutions for complex tasks."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "id": "B18N5YbqIKJB",
        "outputId": "7986c716-0cf0-4ba4-efc0-f4c8c4e0c0c5"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**Least-to-Most Prompting Response:**\n",
              "Okay, I understand the detailed breakdown of the task. Let's start by addressing each step with specific actions and considerations.\n",
              "\n",
              "**1) Define the Problem and Objectives:**\n",
              "\n",
              "*   **1.1) Specify the Prediction Target:**  I will predict the **closing price** of a specific stock.  Let's choose **Apple (AAPL)** as the target stock for this example.\n",
              "*   **1.2) Define the Prediction Horizon:** I will predict the closing price **one day into the future**. This is a short-term prediction.\n",
              "*   **1.3) Determine Evaluation Metrics:** I will use **Root Mean Squared Error (RMSE)** to measure the magnitude of the prediction errors and **directional accuracy** (percentage of correct up/down predictions) to assess the model's ability to predict the direction of price movement.\n",
              "*   **1.4) Establish a Baseline:** My baseline will be a **naive prediction:**  Tomorrow's closing price will be the same as today's closing price.  I will calculate the RMSE and directional accuracy of this baseline on the test set to compare against my model.\n",
              "\n",
              "**2) Data Acquisition and Preparation:**\n",
              "\n",
              "*   **2.1) Identify Data Sources:** I will use **Yahoo Finance** to obtain historical stock prices for AAPL.  I will also consider incorporating **financial news articles from a source like NewsAPI** to potentially capture sentiment.\n",
              "*   **2.2) Data Collection:** I will use the `yfinance` Python library to download historical AAPL stock data. I will write a script to fetch data from Yahoo Finance for the past 5 years (adjust as needed based on data availability and computational resources).  I will also explore the NewsAPI to collect relevant news articles during the same period.\n",
              "*   **2.3) Data Cleaning:**\n",
              "    *   **Missing Values:** I will check for missing values in the historical price data. If any exist, I will use **linear interpolation** to fill them. For news data, I will handle missing sentiment scores (if applicable) by using the mean sentiment score.\n",
              "    *   **Outliers:** I will identify outliers in the price data using the **Interquartile Range (IQR) method**.  Values outside of 1.5 times the IQR from the first and third quartiles will be considered outliers. I will cap these outliers to the 95th and 5th percentile values respectively, rather than removing them entirely, to avoid losing potentially valuable information.\n",
              "    *   **Data Errors:** I will visually inspect the data for any obvious errors or inconsistencies (e.g., negative prices).\n",
              "*   **2.4) Feature Engineering:** I will create the following features:\n",
              "    *   **Moving Averages:** 7-day, 30-day, and 90-day moving averages of the closing price.\n",
              "    *   **Relative Strength Index (RSI):** 14-day RSI.\n",
              "    *   **Moving Average Convergence Divergence (MACD):** Calculated using 12-day and 26-day Exponential Moving Averages (EMAs).\n",
              "    *   **Volatility:** 14-day standard deviation of daily returns.\n",
              "    *   **Lagged Prices:**  Lagged closing prices for the previous 1, 2, and 3 days.\n",
              "    *   **Sentiment Score:** If news data is included, I will calculate a daily sentiment score based on the news articles related to AAPL.\n",
              "*   **2.5) Data Transformation:** I will use **StandardScaler** from scikit-learn to scale all numerical features to have zero mean and unit variance. This will help improve the performance of many machine learning algorithms.\n",
              "\n",
              "**3) Model Selection:**\n",
              "\n",
              "*   **3.1) Choose Potential Models:** I will start with the following models:\n",
              "    *   **Linear Regression:** As a simple baseline.\n",
              "    *   **Random Forest:** To capture non-linear relationships.\n",
              "    *   **LSTM (Long Short-Term Memory) Network:**  To leverage the sequential nature of the time series data.\n",
              "*   **3.2) Consider Model Complexity:** I will start with relatively simple versions of each model and gradually increase complexity if needed. For example, I will begin with a shallow Random Forest (e.g., max_depth=5) and a small LSTM network (e.g., one or two LSTM layers with a small number of units).\n",
              "\n",
              "**4) Model Training and Validation:**\n",
              "\n",
              "*   **4.1) Split Data:** I will split the data into training, validation, and testing sets using a time-based split:\n",
              "    *   **Training Set:** 80% of the data (earliest data).\n",
              "    *   **Validation Set:** 10% of the data (middle data).\n",
              "    *   **Test Set:** 10% of the data (most recent data).\n",
              "*   **4.2) Train Models:** I will train each of the chosen models on the training data. For the LSTM, I will use a batch size of 32 and train for 10-20 epochs, monitoring the validation loss to prevent overfitting.\n",
              "*   **4.3) Hyperparameter Tuning:** I will use **RandomizedSearchCV** from scikit-learn to tune the hyperparameters of the Random Forest model. For the LSTM, I will manually adjust the number of layers, the number of units per layer, and the learning rate based on the validation loss.\n",
              "*   **4.4) Evaluate on Validation Set:** I will evaluate the performance of each trained model on the validation set using RMSE and directional accuracy.\n",
              "\n",
              "**5) Model Testing and Refinement:**\n",
              "\n",
              "*   **5.1) Test on Test Set:** I will select the best-performing model (based on validation set performance) and evaluate it on the test set.\n",
              "*   **5.2) Analyze Results:** I will analyze the model's predictions on the test set, looking for patterns in the errors. I will also examine the feature importance from the Random Forest model to understand which features are most influential.\n",
              "*   **5.3) Refine Model:** Based on the analysis, I will consider:\n",
              "    *   Adding or removing features.\n",
              "    *   Trying different models (e.g., Gradient Boosting).\n",
              "    *   Adjusting hyperparameters.\n",
              "    *   Collecting more data (e.g., longer historical period).\n",
              "*   **5.4) Iterate:** I will repeat steps 4 and 5 until I achieve satisfactory performance on the test set.\n",
              "\n",
              "**6) Deployment and Monitoring (Optional):**\n",
              "\n",
              "*   This step is beyond the scope of this initial exercise, but I acknowledge its importance for real-world applications.\n",
              "\n",
              "This is a comprehensive plan for developing a stock price prediction model. I will now proceed with implementing these steps, starting with data acquisition and preparation."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "ltm_prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        (\"system\", \"You are an AI that can break down complex problems into simpler sub-problems.\"),\n",
        "        (\"human\", \"\"\"Break down this complex task into smaller, manageable steps:\n",
        "          Task: {input}\n",
        "          Steps:\n",
        "          1)\"\"\"),\n",
        "    ]\n",
        ")\n",
        "\n",
        "def ltm_response(task):\n",
        "    steps_chain = ltm_prompt | llm\n",
        "    steps = steps_chain.invoke({\"input\": task}).content\n",
        "\n",
        "    # Now solve each step\n",
        "    solve_prompt = ChatPromptTemplate.from_messages(\n",
        "        [\n",
        "            (\"system\", \"You are an AI that can solve problems step by step.\"),\n",
        "            (\"human\", \"\"\"Solve each step of this task:\n",
        "                Task: {task}\n",
        "                Steps:\n",
        "                {steps}\n",
        "                Solutions:\"\"\"\n",
        "            ),\n",
        "        ]\n",
        "    )\n",
        "    solve_chain = solve_prompt | llm\n",
        "    return solve_chain.invoke({\"task\": task, \"steps\": steps}).content\n",
        "\n",
        "task = \"Develop a machine learning model to predict stock prices\"\n",
        "response = ltm_response(task)\n",
        "\n",
        "display(Markdown(f\"**Least-to-Most Prompting Response:**\\n{response}\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IXPjR6y3wbm8"
      },
      "source": [
        "# 🔗 Prompt Chaining\n",
        "\n",
        "Prompt Chaining is a method of breaking down complex tasks into a series of simpler, interconnected prompts.\n",
        "\n",
        "## Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Use the output of one prompt as input for the next in a sequence.\n",
        "\n",
        "* ⚙️ **Process:**\n",
        "  * Divide the main task into smaller, manageable sub-tasks\n",
        "  * Create a series of prompts, each addressing a sub-task\n",
        "  * Pass results from each step to inform subsequent prompts\n",
        "\n",
        "* 🌟 **Advantages:**\n",
        "  * Handles complex, multi-stage problems more effectively\n",
        "  * Improves overall task performance and accuracy\n",
        "\n",
        "* 💼 **Applications:** Data analysis, content creation, multi-step reasoning tasks.\n",
        "\n",
        "* 🚀**Implementation:**\n",
        "  * Design a logical sequence of prompts\n",
        "  * Ensure each prompt builds on previous results\n",
        "  * Manage context and token limits across the chain\n",
        "\n",
        "* ⚖️ **Challenges:**\n",
        "  * Error propagation through the chain\n",
        "  * Maintaining coherence across multiple prompts\n",
        "\n",
        "* 📝 **Example structure:**\n",
        "  * Step 1: [Initial prompt]\n",
        "  * Step 2: Given [result from Step 1], now [next sub-task]\n",
        "  * Step 3: Using [results from Steps 1 and 2], [final sub-task]\n",
        "\n",
        "* 🔄 **Variations:** Can be combined with other techniques like CoT or ReAct for enhanced performance."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 104
        },
        "id": "O75bD7rywb0Y",
        "outputId": "499e7fb1-9735-4e47-bda3-f8680dd194a0"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**Prompt Chaining Response:**\n",
              "*   Quantum computing uses quantum mechanics principles like superposition and entanglement to solve complex problems that classical computers cannot.\n",
              "*   Qubits, unlike classical bits, can exist in multiple states simultaneously, allowing quantum computers to explore numerous possibilities at once.\n",
              "*   Quantum computing has the potential to revolutionize fields like medicine, materials science, and AI, despite being in its early stages of development."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "def prompt_chaining(topic):\n",
        "    overview_prompt = ChatPromptTemplate.from_messages(\n",
        "        [\n",
        "            (\"system\", \"You are an AI that can generate brief overviews of topics.\"),\n",
        "            (\"human\", \"Generate a brief overview of {input}:\"),\n",
        "        ]\n",
        "      )\n",
        "    overview_chain = overview_prompt | llm\n",
        "    overview = overview_chain.invoke({\"input\": topic}).content\n",
        "\n",
        "    key_points_prompt = ChatPromptTemplate.from_messages(\n",
        "        [\n",
        "            (\"system\", \"You are an AI that can extract key points from overviews.\"),\n",
        "            (\"human\", f\"\"\"Based on this overview, list 3 key points:\n",
        "              {overview}\n",
        "\n",
        "              Key points:\"\"\"),\n",
        "        ]\n",
        "      )\n",
        "    keypoints_chain = key_points_prompt | llm\n",
        "    return keypoints_chain.invoke({\"overview\": overview}).content\n",
        "\n",
        "topic = \"quantum computing\"\n",
        "response = prompt_chaining(topic)\n",
        "display(Markdown(f\"**Prompt Chaining Response:**\\n{response}\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QKNT2Y-Fwtsg"
      },
      "source": [
        "# 📊 Graph Prompting\n",
        "**Note:** This is a simplified version without usinga graph database\n",
        "\n",
        "Graph Prompting is an advanced method that uses graph structures to guide complex reasoning tasks.\n",
        "\n",
        "## Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Represent problems as interconnected nodes in a graph, with prompts guiding traversal and reasoning.\n",
        "\n",
        "* 📊 **Structure:**\n",
        "  * Nodes represent concepts, sub-tasks, or decision points\n",
        "  * Edges represent relationships or transitions between nodes\n",
        "\n",
        "* ⚙️ **Process:**\n",
        "  * Define the problem as a graph\n",
        "  * Guide the model through the graph using targeted prompts\n",
        "  * Aggregate information from traversed nodes to form a solution\n",
        "\n",
        "* 🌟 **Advantages:**\n",
        "  * Handles complex, interconnected problems\n",
        "  * Allows for non-linear reasoning paths\n",
        "\n",
        "* 💼 **Applications:**\n",
        "  * Multi-step decision making\n",
        "  * Knowledge graph navigation\n",
        "  * Solving problems with multiple dependencies\n",
        "\n",
        "* 🚀 **Implementation:**\n",
        "  * Design the graph structure based on the problem domain\n",
        "  * Craft prompts for node exploration and edge traversal\n",
        "  * Develop strategies for information aggregation across nodes\n",
        "\n",
        "* ⚖️ **Challenges:**\n",
        "  * Designing effective graph structures\n",
        "  * Managing context across multiple graph traversals\n",
        "\n",
        "* 🔄 **Variations:**\n",
        "  * Dynamic graph prompting: Adjust the graph structure based on intermediate results\n",
        "  * Hierarchical graph prompting: Use nested graphs for multi-level reasoning"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 46
        },
        "id": "M7CwC26Zwt7I",
        "outputId": "b9df4f8f-3310-4e04-dd47-78fa91d65a4b"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**Graph Prompting Response:**\n",
              "Red Planet"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "system = \"\"\"You are an AI that can reason over graph-structured knowledge.\"\"\"\n",
        "\n",
        "graph_prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        (\"system\", system),\n",
        "        (\"human\", \"\"\"Given the following graph structure:\n",
        "                    Earth - neighboring planet -> Mars\n",
        "                    Mars - nickname -> Red Planet\n",
        "                    Answer the following question:\n",
        "                    {input}\n",
        "                    Answer:\"\"\"),\n",
        "    ]\n",
        ")\n",
        "\n",
        "chain = graph_prompt | llm\n",
        "question = \"What is the nickname of the neighboring planet to Earth?\"\n",
        "response = chain.invoke({\"input\": question})\n",
        "\n",
        "display(Markdown(f\"**Graph Prompting Response:**\\n{response.content}\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BGn4LyUVxBKi"
      },
      "source": [
        "# 🔄 Recursive Prompting\n",
        "\n",
        "Recursive Prompting is a method where a language model's output is fed back into itself as input for further processing.\n",
        "\n",
        "## Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Use the model's output as input for subsequent prompts, creating a feedback loop.\n",
        "\n",
        "* ⚙️ **Process:**\n",
        "  * Start with an initial prompt\n",
        "  * Use the output to formulate a new, refined prompt\n",
        "  * Repeat the process until a satisfactory result is achieved\n",
        "\n",
        "* 🌟 **Advantages:**\n",
        "  * Enables iterative refinement of responses\n",
        "  * Allows for deeper exploration of complex topics\n",
        "\n",
        "* 💼 **Applications:**\n",
        "  * Text summarization\n",
        "  * Idea generation and brainstorming\n",
        "  * Progressive problem-solving\n",
        "\n",
        "* 🚀 **Implementation:**\n",
        "  * Design a base prompt that can accept its own output\n",
        "  * Implement a stopping condition to prevent infinite loops\n",
        "  * Manage context length as recursion deepens\n",
        "\n",
        "* ⚖️ **Challenges:**\n",
        "  * Avoiding circular reasoning or repetition\n",
        "  * Maintaining coherence across recursive steps\n",
        "\n",
        "* 📝 **Example structure:**\n",
        "  * Initial prompt: [Task description]\n",
        "  * Recursive step: Based on the previous output, [refined task]\n",
        "  * Stopping condition: Continue until [specific criteria met]\n",
        "\n",
        "* 🔄 **Variations:**\n",
        "  * Self-reflection: Use recursion for the model to critique and improve its own outputs\n",
        "  * Depth-limited recursion: Set a maximum number of recursive steps"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 375
        },
        "id": "VltIhYAExBVY",
        "outputId": "cbfbf89e-676d-4468-878a-a83282ce63ce"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**Recursive Prompting Response:**\n",
              "Okay, here are three more detailed follow-up questions, building on the previous set (depth: 4):\n",
              "\n",
              "1.  **(Follow-up to Q1 - Autonomous Weapons Systems Ethics & Regulation): Considering the inherent limitations of current verification methods in ensuring compliance with international regulations on autonomous weapons (e.g., difficulty in proving a weapon's autonomy level or predicting its behavior in complex scenarios), what novel verification techniques, such as formal methods, adversarial testing, or explainable AI, should be explored and developed to enhance the trustworthiness and accountability of these systems, and how can these techniques be standardized and integrated into the development lifecycle of autonomous weapons?** (This question dives into the technical challenges of verifying compliance and asks for specific, potentially cutting-edge solutions, while also considering standardization.)\n",
              "\n",
              "2.  **(Follow-up to Q2 - AI Bias Mitigation & Monitoring): Beyond technical solutions for bias mitigation, how can we foster greater diversity and inclusion within AI development teams and promote ethical awareness among AI practitioners to address the root causes of bias in AI systems, and what specific educational programs or professional certifications could be implemented to ensure that AI developers are equipped with the necessary skills and knowledge to build fair and equitable AI systems?** (This question shifts the focus from purely technical solutions to the human element, exploring the role of diversity, ethics training, and professional development in preventing bias.)\n",
              "\n",
              "3.  **(Follow-up to Q3 - Long-Term AI Impact & Societal Restructuring): Assuming that advanced AI leads to significant job displacement across various sectors, what innovative economic models, such as universal basic income, guaranteed employment, or alternative forms of wealth distribution, should be explored and potentially implemented to mitigate the negative consequences of automation and ensure that all members of society can benefit from the advancements in AI, and what are the potential challenges and trade-offs associated with each of these models?** (This question focuses on the economic implications of advanced AI, specifically job displacement, and asks for concrete solutions while acknowledging the complexities and potential drawbacks of each.)"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "def recursive_prompting(topic, max_depth=3):\n",
        "\n",
        "    system = \"\"\"You are an AI that can generate questions about topics.\"\"\"\n",
        "    base_prompt = ChatPromptTemplate.from_messages(\n",
        "        [\n",
        "            (\"system\", system),\n",
        "            (\"human\", \"Generate three questions about {input}:\"),\n",
        "        ]\n",
        "    )\n",
        "\n",
        "    base_chain = base_prompt | llm\n",
        "    questions = base_chain.invoke({\"input\": topic}).content\n",
        "\n",
        "    for depth in range(1, max_depth):\n",
        "        system = (\n",
        "            \"\"\"You are an AI that can generate more detailed follow-up questions.\"\"\"\n",
        "        )\n",
        "        recursive_prompt = ChatPromptTemplate.from_messages(\n",
        "            [\n",
        "                (\"system\", system),\n",
        "                (\"human\", f\"\"\"Based on these questions:\n",
        "                    {questions}\n",
        "                    Generate three more detailed follow-up questions. Current depth: {max_depth}\"\"\",\n",
        "                ),\n",
        "            ]\n",
        "        )\n",
        "        recursive_chain = recursive_prompt | llm\n",
        "        questions = recursive_chain.invoke({\"questions\": questions, \"max_depth\": max_depth}).content\n",
        "\n",
        "    return questions\n",
        "\n",
        "\n",
        "topic = \"artificial intelligence\"\n",
        "response = recursive_prompting(topic)\n",
        "display(Markdown(f\"**Recursive Prompting Response:**\\n{response}\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "l8TIiYLksBR8"
      },
      "source": [
        "# 💡 Generated Knowledge\n",
        "\n",
        "Generated Knowledge is a method that uses language models to create relevant information before solving a task.\n",
        "\n",
        "## Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Generate task-specific knowledge before addressing the main problem.\n",
        "\n",
        "* ⚙️ **Process:**\n",
        "  * Prompt the model to generate relevant facts or context\n",
        "  * Use this generated knowledge as input for the primary task\n",
        "  * Solve the main problem with enhanced context\n",
        "\n",
        "* 🌟 **Advantages:**\n",
        "  * Improves performance on tasks requiring specific knowledge\n",
        "  * Allows for dynamic, task-specific information generation\n",
        "\n",
        "* 💼 **Applications:**\n",
        "  * Question answering\n",
        "  * Contextual reasoning\n",
        "  * Domain-specific problem solving\n",
        "\n",
        "* 🚀 **Implementation:**\n",
        "  * Design prompts to elicit relevant knowledge generation\n",
        "  * Integrate generated knowledge into the main task prompt\n",
        "  * Evaluate and filter generated knowledge for relevance\n",
        "\n",
        "* ⚖️ **Challenges:**\n",
        "  * Ensuring accuracy of generated knowledge\n",
        "  * Balancing knowledge generation with task completion\n",
        "\n",
        "* 📝 **Example structure:**\n",
        "  * Step 1: Generate knowledge about [topic relevant to task]\n",
        "  * Step 2: Using the generated information, solve [main task]\n",
        "\n",
        "* 🔄 **Variations:**\n",
        "  * Multi-step knowledge generation\n",
        "  * Combining generated knowledge with external sources"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 737
        },
        "id": "-92ApoB4svfM",
        "outputId": "4cc7f5d4-21a3-43da-9b83-f97268a7d8a5"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**Generated Knowledge:**\n",
              "Okay, here's a brief summary of key facts and concepts related to quantum computing:\n",
              "\n",
              "**What is Quantum Computing?**\n",
              "\n",
              "*   **Fundamentally Different:** Quantum computing is a new paradigm of computation that leverages the principles of quantum mechanics to solve complex problems that are intractable for classical computers.\n",
              "*   **Quantum Mechanics:** It relies on phenomena like superposition and entanglement to perform computations in a fundamentally different way than classical computers, which use bits representing 0 or 1.\n",
              "\n",
              "**Key Concepts:**\n",
              "\n",
              "*   **Qubit (Quantum Bit):** The basic unit of information in a quantum computer. Unlike a classical bit, a qubit can exist in a superposition of states, representing 0, 1, or a combination of both simultaneously.\n",
              "*   **Superposition:** The ability of a qubit to be in multiple states (0 and 1) at the same time. This allows quantum computers to explore many possibilities concurrently.\n",
              "*   **Entanglement:** A quantum mechanical phenomenon where two or more qubits become linked together in such a way that the state of one instantly influences the state of the others, regardless of the distance separating them. Entanglement enables powerful correlations and parallel computations.\n",
              "*   **Quantum Gates:** Analogous to logic gates in classical computers, quantum gates manipulate the state of qubits. These gates are represented by matrices and perform unitary transformations on the qubits.\n",
              "*   **Quantum Algorithm:** A sequence of quantum gates designed to perform a specific computation. Well-known examples include Shor's algorithm (for factoring large numbers) and Grover's algorithm (for searching unsorted databases).\n",
              "*   **Decoherence:** A major challenge in quantum computing. It refers to the loss of quantum information due to interactions with the environment, causing qubits to lose their superposition and entanglement. Maintaining coherence is crucial for accurate computations.\n",
              "\n",
              "**Potential Applications:**\n",
              "\n",
              "*   **Drug Discovery and Materials Science:** Simulating molecular interactions to design new drugs and materials.\n",
              "*   **Cryptography:** Breaking existing encryption algorithms (like RSA) and developing new, quantum-resistant cryptography.\n",
              "*   **Optimization:** Solving complex optimization problems in areas like logistics, finance, and machine learning.\n",
              "*   **Artificial Intelligence:** Enhancing machine learning algorithms and enabling new AI capabilities.\n",
              "*   **Financial Modeling:** Improving risk analysis and portfolio optimization.\n",
              "\n",
              "**Current Status and Challenges:**\n",
              "\n",
              "*   **Early Stage:** Quantum computing is still in its early stages of development.\n",
              "*   **Hardware Challenges:** Building and maintaining stable and scalable quantum computers is extremely difficult. Different qubit technologies are being explored (e.g., superconducting qubits, trapped ions, photonic qubits).\n",
              "*   **Software Development:** Developing quantum algorithms and software tools is a complex task.\n",
              "*   **Error Correction:** Quantum error correction is essential to mitigate the effects of decoherence and ensure accurate computations.\n",
              "*   **Scalability:** Increasing the number of qubits while maintaining their coherence and control is a major challenge.\n",
              "\n",
              "**In Summary:** Quantum computing holds immense potential to revolutionize various fields by solving problems currently intractable for classical computers. However, significant technological and scientific challenges remain before it becomes a widely accessible and practical technology.\n",
              "\n",
              "**Question:**\n",
              "What are the potential applications of quantum computing in cryptography?\n",
              "\n",
              "**Generated Knowledge Response:**\n",
              "Quantum computing has the potential to break existing encryption algorithms (like RSA) and develop new, quantum-resistant cryptography."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "generate_knowledge_prompt = ChatPromptTemplate.from_messages(\n",
        "            [\n",
        "                (\"system\", \"You are an AI that can generate relevant knowledge about a given topic.\"),\n",
        "                (\"human\", \"Generate a brief summary of key facts and concepts related to {topic}:\"\n",
        "                ),\n",
        "            ]\n",
        "        )\n",
        "\n",
        "answer_question_prompt = ChatPromptTemplate.from_messages(\n",
        "            [\n",
        "                (\"system\", \"You are an AI assistant that can answer questions based on given knowledge.\"),\n",
        "                (\"human\", \"\"\"Use the following generated knowledge to answer the question:\n",
        "                  Generated Knowledge:\n",
        "                  {knowledge}\n",
        "                  Question: {question}\n",
        "                  Answer:\"\"\"\n",
        "                )\n",
        "            ]\n",
        "        )\n",
        "\n",
        "def generated_knowledge_response(topic, question):\n",
        "    # Step 1: Generate relevant knowledge\n",
        "    generate_knowledge_chain = generate_knowledge_prompt | llm\n",
        "    generated_knowledge = generate_knowledge_chain.invoke({\"topic\": topic}).content\n",
        "\n",
        "    # Step 2: Use the generated knowledge to answer the question\n",
        "    answer_question_chain = answer_question_prompt | llm\n",
        "    answer = answer_question_chain.invoke(\n",
        "        {\"knowledge\": generated_knowledge, \"question\": question}\n",
        "    ).content\n",
        "\n",
        "    return generated_knowledge, answer\n",
        "\n",
        "\n",
        "# Example usage\n",
        "topic = \"quantum computing\"\n",
        "question = \"What are the potential applications of quantum computing in cryptography?\"\n",
        "\n",
        "generated_knowledge, response = generated_knowledge_response(topic, question)\n",
        "\n",
        "display(\n",
        "    Markdown(\n",
        "        f\"\"\"**Generated Knowledge:**\n",
        "{generated_knowledge}\n",
        "\n",
        "**Question:**\n",
        "{question}\n",
        "\n",
        "**Generated Knowledge Response:**\n",
        "{response}\"\"\"\n",
        "    )\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Fq4lkZvNsvtE"
      },
      "source": [
        "# ⚙️ Automatic Reasoning and Tool-Use (ART)\n",
        "\n",
        "ART is an advanced prompting method that combines reasoning with automated tool selection and use.\n",
        "\n",
        "## Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Enable language models to autonomously reason about problems and select/use appropriate tools.\n",
        "\n",
        "* 🛠️ **Components:**\n",
        "  * Reasoning module\n",
        "  * Tool selection mechanism\n",
        "  * Tool use interface\n",
        "\n",
        "* ⚙️ **Process:**\n",
        "  * Analyze the problem through reasoning\n",
        "  * Identify and select relevant tools\n",
        "  * Use tools to gather information or perform actions\n",
        "  * Integrate tool outputs into the reasoning process\n",
        "\n",
        "* 🌟 **Advantages:**\n",
        "  * Enhances problem-solving capabilities\n",
        "  * Allows for more complex, multi-step tasks\n",
        "\n",
        "* 💼 **Applications:**\n",
        "  * Data analysis\n",
        "  * Web-based research\n",
        "  * Complex decision-making scenarios\n",
        "\n",
        "* 🚀 **Implementation:**\n",
        "  * Define a set of available tools and their functions\n",
        "  * Design prompts that encourage tool consideration\n",
        "  * Implement feedback loops between reasoning and tool use\n",
        "\n",
        "* ⚖️ **Challenges:**\n",
        "  * Ensuring appropriate tool selection\n",
        "  * Managing context across multiple tool uses\n",
        "\n",
        "* 📝 **Example structure:**\n",
        "  * Thought: [Reasoning about the problem]\n",
        "  * Tool Selection: [Choose appropriate tool]\n",
        "  * Tool Use: [Apply selected tool]\n",
        "  * Integration: [Incorporate tool output into reasoning]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 81
        },
        "id": "TV6VCvTNtkWc",
        "outputId": "1e2f45b3-0d42-402c-8187-2967219fbb92"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "**Automatic Reasoning and Tool-Use (ART) Response:**\n",
              "Task: Calculate the number of days between the current date and July 4, 2025. Then, provide the weather forecast for New York City.\n",
              "Okay, I will break down the task into smaller, manageable steps. I will explain my reasoning for each step and use the available tools when necessary to solve the problem.\n"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "from datetime import datetime, date\n",
        "# Define available tools\n",
        "def calculate_days(date_string):\n",
        "    target_date = datetime.strptime(date_string, \"%Y-%m-%d\").date()\n",
        "    current_date = date.today()\n",
        "    return (target_date - current_date).days\n",
        "\n",
        "tools = {\n",
        "    \"calculator\": lambda x: eval(x),\n",
        "    \"date\": lambda: date.today().strftime(\"%Y-%m-%d\"),\n",
        "    \"weather\": lambda city: f\"The weather in {city} is sunny with a high of 25°C.\",\n",
        "    \"days_between\": calculate_days\n",
        "}\n",
        "\n",
        "# ART Prompt\n",
        "art_prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        SystemMessage(\n",
        "            content=\"\"\"You are an AI assistant capable of breaking down complex tasks, identifying necessary tools, and applying them to solve problems. You have access to the following tools:\n",
        "              1. calculator: Performs mathematical calculations. Input should be a mathematical expression.\n",
        "              2. date: Returns the current date.\n",
        "              3. weather: Provides weather information for a given city.\n",
        "              4. days_between: Calculates the number of days between the current date and a given date (format: YYYY-MM-DD).\n",
        "              For each step in your reasoning, if a tool is needed, specify it in the following JSON format:\n",
        "              {\"tool\": \"tool_name\", \"input\": \"tool_input\"}\n",
        "              Your final answer should not be in JSON format.\"\"\"\n",
        "        ),\n",
        "        HumanMessage(\n",
        "            content=\"\"\"Task: {task}\n",
        "            Break down this task and solve it step by step. For each step, explain your reasoning and use tools when necessary.\n",
        "            Your response:\"\"\"\n",
        "        ),\n",
        "    ]\n",
        ")\n",
        "\n",
        "def art_response(task):\n",
        "    messages = art_prompt.format_prompt(task=task).to_messages()\n",
        "    raw_response = llm.invoke(messages).content\n",
        "    # Process the response to use tools\n",
        "    lines = raw_response.split(\"\\n\")\n",
        "    processed_response = []\n",
        "    for line in lines:\n",
        "        if line.strip().startswith(\"{\") and line.strip().endswith(\"}\"):\n",
        "            try:\n",
        "                tool_call = json.loads(line)\n",
        "                if tool_call[\"tool\"] in tools:\n",
        "                    tool_result = tools[tool_call[\"tool\"]](tool_call[\"input\"])\n",
        "                    processed_response.append(\n",
        "                        f\"Using {tool_call['tool']}: {tool_call['input']}\"\n",
        "                    )\n",
        "                    processed_response.append(f\"Result: {tool_result}\")\n",
        "                else:\n",
        "                    processed_response.append(\n",
        "                        f\"Error: Tool '{tool_call['tool']}' not found.\"\n",
        "                    )\n",
        "            except json.JSONDecodeError:\n",
        "                processed_response.append(line)\n",
        "        else:\n",
        "            processed_response.append(line)\n",
        "    return \"\\n\".join(processed_response)\n",
        "\n",
        "# Example usage\n",
        "task = \"Calculate the number of days between the current date and July 4, 2025. Then, provide the weather forecast for New York City.\"\n",
        "response = art_response(task)\n",
        "display(\n",
        "    Markdown(\n",
        "        f\"\"\"**Automatic Reasoning and Tool-Use (ART) Response:**\n",
        "Task: {task}\n",
        "{response}\"\"\"\n",
        "    )\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "s7_dJXb2tk-D"
      },
      "source": [
        "# 🛠️ Automatic Prompt Engineer (APE)\n",
        "\n",
        "APE is a method for automatically generating and optimizing prompts for language models.\n",
        "\n",
        "## Key points:\n",
        "\n",
        "* 🔑 **Core concept:** Use AI to create and refine prompts, reducing manual engineering effort.\n",
        "\n",
        "* ⚙️ **Process:**\n",
        "  * Generate candidate prompts\n",
        "  * Evaluate prompt performance\n",
        "  * Iteratively optimize prompts\n",
        "\n",
        "* 🛠️ **Components:**\n",
        "  * Prompt generator\n",
        "  * Performance evaluator\n",
        "  * Optimization algorithm\n",
        "\n",
        "* 🌟 **Advantages:**\n",
        "  * Discovers effective prompts automatically\n",
        "  * Adapts to different tasks and model architectures\n",
        "\n",
        "* 💼 **Applications:**\n",
        "  * Task-specific prompt optimization\n",
        "  * Improving model performance across various domains\n",
        "\n",
        "* 🚀 **Implementation:**\n",
        "  * Define task and evaluation metrics\n",
        "  * Use large language models to generate initial prompts\n",
        "  * Apply optimization techniques (e.g., genetic algorithms, gradient-based methods)\n",
        "\n",
        "* ⚖️ **Challenges:**\n",
        "  * Balancing exploration and exploitation in prompt space\n",
        "  *Ensuring generated prompts are interpretable and safe\n",
        "  \n",
        "* 🔄 **Variations:**\n",
        "  * Multi-task APE: Optimize prompts for multiple related tasks\n",
        "  * Constrained APE: Generate prompts within specific guidelines or structures"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "id": "CLEMZN8st7KF",
        "outputId": "5df031be-05c7-4c4e-a75d-034793f866e7"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Iteration 1\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "**Generated Prompts:**\n",
              "Task: Given a news article about a recent scientific discovery, write a short, engaging summary suitable for sharing on social media (e.g., Twitter, Facebook). The summary should be no more than 280 characters and should include a relevant hashtag.\n",
              "\n",
              "Prompt 1:\n",
              "Summarize the following news article in under 280 characters for social media. Include a relevant hashtag.\n",
              "\n",
              "[News Article Text]\n",
              "\n",
              "Prompt 2:\n",
              "Imagine you're a science communicator tasked with sharing the following scientific discovery on Twitter. Condense the article into a compelling summary of no more than 280 characters. What would you tweet? Include a relevant hashtag to increase visibility.\n",
              "\n",
              "[News Article Text]\n",
              "\n",
              "Prompt 3:\n",
              "Read the news article below. Extract the most important information and rewrite it as a short, attention-grabbing social media post (max 280 characters). Focus on the impact or significance of the discovery. Suggest a relevant hashtag.\n",
              "\n",
              "[News Article Text]\n"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "**Prompt Evaluation:**\n",
              "Okay, I understand. I'm ready to evaluate prompts based on clarity, specificity, and potential to elicit high-quality responses, and provide scores and explanations in the requested format. Please provide the task and the prompts you want me to evaluate. I'm looking forward to helping you improve your prompt engineering!\n"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Failed to generate valid prompts or scores in this iteration.\n",
            "\n",
            "Iteration 2\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "**Generated Prompts:**\n",
              "Task: Given a news article about a recent scientific discovery, write a short, engaging summary suitable for sharing on social media (e.g., Twitter, Facebook). The summary should be no more than 280 characters and should include a relevant hashtag.\n",
              "\n",
              "Prompt 1:\n",
              "Summarize the following news article in under 280 characters for social media. Include a relevant hashtag.\n",
              "\n",
              "[News Article Text]\n",
              "\n",
              "Prompt 2:\n",
              "Imagine you are a science communicator tasked with sharing the following scientific discovery on Twitter. Condense the article below into a tweet (under 280 characters) that is both informative and engaging. Suggest a relevant hashtag to increase visibility.\n",
              "\n",
              "[News Article Text]\n",
              "\n",
              "Prompt 3:\n",
              "Read the news article provided. Extract the most important information and rewrite it as a short, attention-grabbing social media post (max 280 characters). Focus on making the science accessible to a general audience. Include a relevant and trending hashtag.\n",
              "\n",
              "[News Article Text]\n"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "**Prompt Evaluation:**\n",
              "Okay, I understand. I'm ready to evaluate prompts based on the task provided and the prompts themselves, using a 1-10 scoring system and providing a brief explanation of each prompt's strengths and weaknesses. I will adhere to the specified output format.\n",
              "\n",
              "Let's assume we have the following example:\n",
              "\n",
              "**Task:** Write a short story about a sentient toaster who falls in love with a blender.\n",
              "\n",
              "**Prompts:**\n",
              "\n",
              "Prompt 1: Write a story about a toaster.\n",
              "\n",
              "Prompt 2:  Imagine a world where kitchen appliances have feelings. Tell a story about a toaster named \"Rusty\" who develops an unexpected affection for a sleek, modern blender. Explore the challenges and joys of their unconventional romance.\n",
              "\n",
              "Prompt 3:  Compose a narrative, approximately 500 words in length, detailing the burgeoning romance between a self-aware toaster and a blender. Consider themes of societal acceptance, technological evolution, and the definition of love in a world increasingly dominated by artificial intelligence. Include at least three instances of dialogue between the toaster and the blender.\n",
              "\n",
              "Here's my evaluation:\n",
              "\n",
              "Prompt 1:\n",
              "Score: 4/10\n",
              "Evaluation: This prompt is too vague. While it fulfills the basic requirement of writing a story about a toaster, it lacks specificity and provides no guidance on the story's plot, tone, or themes. It's likely to elicit a wide range of responses, many of which may not be particularly creative or engaging. The lack of detail makes it difficult for the language model to understand the desired output.\n",
              "\n",
              "Prompt 2:\n",
              "Score: 7/10\n",
              "Evaluation: This prompt is significantly better than Prompt 1. It provides more context and direction by introducing the concept of sentient appliances and a specific scenario: a toaster named Rusty falling in love with a blender. It also suggests exploring the challenges and joys of their romance, which helps to focus the narrative. However, it could be improved by specifying a desired length or including more specific instructions regarding themes or plot points.\n",
              "\n",
              "Prompt 3:\n",
              "Score: 9/10\n",
              "Evaluation: This is the strongest prompt. It's clear, specific, and provides ample guidance for the language model. It specifies the approximate length (500 words), introduces themes (societal acceptance, technological evolution, definition of love), and requires dialogue. This level of detail increases the likelihood of receiving a well-structured, engaging, and relevant story. The inclusion of AI as a theme adds another layer of complexity and interest.\n",
              "\n",
              "Your evaluation: This evaluation demonstrates my ability to assess prompts based on clarity, specificity, and potential to elicit high-quality responses. I have provided scores and justifications for each prompt, adhering to the specified format. I am ready to evaluate any task and set of prompts you provide.\n"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Best prompt so far (score 9/10):\n",
            "Read the news article provided. Extract the most important information and rewrite it as a short, attention-grabbing social media post (max 280 characters). Focus on making the science accessible to a general audience. Include a relevant and trending hashtag.\n",
            "\n",
            "[News Article Text]\n",
            "\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "**Final Best Prompt:**\n",
              "Read the news article provided. Extract the most important information and rewrite it as a short, attention-grabbing social media post (max 280 characters). Focus on making the science accessible to a general audience. Include a relevant and trending hashtag.\n",
              "\n",
              "[News Article Text]\n",
              "\n",
              "**Final Result:**\n",
              "Okay, I need the news article to complete the task. Please provide the text of the news article. Once you provide the text, I will:\n",
              "\n",
              "1.  **Identify the most important information.**\n",
              "2.  **Simplify the science for a general audience.**\n",
              "3.  **Craft a short, attention-grabbing social media post (under 280 characters).**\n",
              "4.  **Include a relevant and trending hashtag.**\n",
              "\n",
              "Then, I will explain quantum entanglement to a 10-year-old.\n"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "import re\n",
        "# APE Prompt Generation\n",
        "ape_generation_prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        SystemMessage(\n",
        "            content=\"You are an AI specialized in creating effective prompts for language models.\"\n",
        "        ),\n",
        "        HumanMessage(\n",
        "            content=\"\"\"Task: Create a prompt that will help a language model perform the following task effectively:\n",
        "\n",
        "          {task}\n",
        "\n",
        "          Generate 3 different prompts for this task. Each prompt should be designed to elicit a high-quality response from a language model. Consider different angles, formats, and instructions that might lead to better results.\n",
        "\n",
        "          Your response should be in the following format:\n",
        "\n",
        "          Prompt 1:\n",
        "          [Your first prompt here]\n",
        "\n",
        "          Prompt 2:\n",
        "          [Your second prompt here]\n",
        "\n",
        "          Prompt 3:\n",
        "          [Your third prompt here]\n",
        "\n",
        "          Generated Prompts:\"\"\"\n",
        "                  ),\n",
        "              ]\n",
        "          )\n",
        "\n",
        "# APE Evaluation\n",
        "ape_evaluation_prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        HumanMessage(\n",
        "            content=\"You are an AI specialized in evaluating the effectiveness of prompts for language models.\"\n",
        "        ),\n",
        "        HumanMessage(\n",
        "            content=\"\"\"Evaluate the following prompts for their effectiveness in accomplishing this task:\n",
        "            Task: {task}\n",
        "            {prompts}\n",
        "            For each prompt, provide a score from 1-10 and a brief explanation of its strengths and weaknesses. Consider factors such as clarity, specificity, and potential to elicit high-quality responses.\n",
        "            Your evaluation should be in the following format:\n",
        "            Prompt 1:\n",
        "            Score: [score]/10\n",
        "            Evaluation: [Your evaluation here]\n",
        "\n",
        "            Prompt 2:\n",
        "            Score: [score]/10\n",
        "            Evaluation: [Your evaluation here]\n",
        "\n",
        "            Prompt 3:\n",
        "            Score: [score]/10\n",
        "            Evaluation: [Your evaluation here]\n",
        "\n",
        "            Your evaluation:\"\"\"\n",
        "                    ),\n",
        "                ]\n",
        "            )\n",
        "\n",
        "def generate_prompts(task):\n",
        "    messages = ape_generation_prompt.format_prompt(task=task).to_messages()\n",
        "    return llm.invoke(messages).content\n",
        "\n",
        "def evaluate_prompts(task, prompts):\n",
        "    messages = ape_evaluation_prompt.format_prompt(\n",
        "        task=task, prompts=prompts\n",
        "    ).to_messages()\n",
        "    return llm.invoke(messages).content\n",
        "\n",
        "def test_prompt(prompt, task):\n",
        "    test_prompt = ChatPromptTemplate.from_messages(\n",
        "        [\n",
        "            HumanMessage(content=\"You are an AI assistant completing a given task.\"),\n",
        "            HumanMessage(content=f\"{prompt}\\n\\nTask: {task}\"),\n",
        "        ]\n",
        "    )\n",
        "    messages = test_prompt.format_prompt().to_messages()\n",
        "    return llm.invoke(messages).content\n",
        "\n",
        "def parse_prompts(generated_prompts):\n",
        "    prompts = re.findall(\n",
        "        r\"Prompt \\d+:\\n(.*?)(?=\\n\\nPrompt \\d+:|$)\", generated_prompts, re.DOTALL\n",
        "    )\n",
        "    return [prompt.strip() for prompt in prompts if prompt.strip()]\n",
        "\n",
        "def parse_scores(evaluation):\n",
        "    scores = re.findall(r\"Score: (\\d+)/10\", evaluation)\n",
        "    return [int(score) for score in scores if score.isdigit()]\n",
        "\n",
        "def ape_process(task, iterations=2):\n",
        "    best_prompt = \"\"\n",
        "    best_score = 0\n",
        "\n",
        "    for i in range(iterations):\n",
        "        print(f\"Iteration {i+1}\")\n",
        "\n",
        "        # Generate prompts\n",
        "        generated_prompts = generate_prompts(task)\n",
        "        display(Markdown(f\"**Generated Prompts:**\\n{generated_prompts}\"))\n",
        "\n",
        "        # Evaluate prompts\n",
        "        evaluation = evaluate_prompts(task, generated_prompts)\n",
        "        display(Markdown(f\"**Prompt Evaluation:**\\n{evaluation}\"))\n",
        "\n",
        "        # Parse prompts and scores\n",
        "        prompts = parse_prompts(generated_prompts)\n",
        "        scores = parse_scores(evaluation)\n",
        "\n",
        "        # Ensure we have valid prompts and scores\n",
        "        if prompts and scores:\n",
        "            # Make sure we have the same number of prompts and scores\n",
        "            min_length = min(len(prompts), len(scores))\n",
        "            prompts = prompts[:min_length]\n",
        "            scores = scores[:min_length]\n",
        "\n",
        "            if max(scores) > best_score:\n",
        "                best_score = max(scores)\n",
        "                best_prompt = prompts[scores.index(max(scores))]\n",
        "\n",
        "            print(f\"Best prompt so far (score {best_score}/10):\")\n",
        "            print(best_prompt)\n",
        "        else:\n",
        "            print(\"Failed to generate valid prompts or scores in this iteration.\")\n",
        "\n",
        "        print()\n",
        "\n",
        "    # If we didn't find a good prompt, use a default one\n",
        "    if not best_prompt:\n",
        "        best_prompt = f\"Please {task}\"\n",
        "        print(\"Using default prompt due to generation issues.\")\n",
        "\n",
        "    # Test the best prompt\n",
        "    final_result = test_prompt(best_prompt, task)\n",
        "    return best_prompt, final_result\n",
        "\n",
        "# Example usage\n",
        "task = \"Explain the concept of quantum entanglement to a 10-year-old.\"\n",
        "\n",
        "best_prompt, final_result = ape_process(task)\n",
        "\n",
        "display(\n",
        "    Markdown(\n",
        "        f\"\"\"**Final Best Prompt:**\n",
        "{best_prompt}\n",
        "\n",
        "**Final Result:**\n",
        "{final_result}\"\"\"\n",
        "    )\n",
        ")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7BmVDaUebM3Y"
      },
      "outputs": [],
      "source": []
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
